package emulator.hardware.nmos6502.commands;

import emulator.EmulatorException;
import emulator.hardware.HwByte;
import emulator.hardware.nmos6502.Command;
import emulator.hardware.nmos6502.CommandSet;
import emulator.hardware.nmos6502.Cpu6502;
import emulator.hardware.nmos6502.Flags6502;
import emulator.hardware.nmos6502.Operand;
import emulator.hardware.nmos6502.operands.Absolute;
import emulator.hardware.nmos6502.operands.AbsoluteX;
import emulator.hardware.nmos6502.operands.AbsoluteY;
import emulator.hardware.nmos6502.operands.Immediate;
import emulator.hardware.nmos6502.operands.IndirectX;
import emulator.hardware.nmos6502.operands.IndirectY;
import emulator.hardware.nmos6502.operands.ZeroPage;
import emulator.hardware.nmos6502.operands.ZeroPageX;

/** CMP (CoMPare accumulator)
 *  
 *  Affects Flags: S Z C
 *  
 *  MODE           SYNTAX       HEX LEN TIM
 *  Immediate     CMP #$44      $C9  2   2
 *  Zero Page     CMP $44       $C5  2   3
 *  Zero Page,X   CMP $44,X     $D5  2   4
 *  Absolute      CMP $4400     $CD  3   4
 *  Absolute,X    CMP $4400,X   $DD  3   4+
 *  Absolute,Y    CMP $4400,Y   $D9  3   4+
 *  Indirect,X    CMP ($44,X)   $C1  2   6
 *  Indirect,Y    CMP ($44),Y   $D1  2   5+
 *  
 *  + add 1 cycle if page boundary crossed
 *  
 *  Compare sets flags as if a subtraction had been carried out. If the value
 *  in the accumulator is equal or greater than the compared value, the Carry
 *  will be set. The equal (Z) and sign (S) flags will be set based on
 *  equality or lack thereof and the sign (i.e. A>=$80) of the accumulator. 
 */
public class CMP implements Command {

	@Override
	public void execute(Cpu6502 cpu, Operand operand) throws EmulatorException {
		HwByte op_n = new HwByte(operand.getByte().getNumber());
		HwByte result = cpu.getAccu();
		Flags6502 flags = cpu.getFlags();
		flags.setCarry(result.getNumber() >= op_n.getNumber());
		op_n.not();
		op_n.inc(1);
		result.inc((int) op_n.getNumber());
		flags.setNZFromValue(result);
		cpu.setFlags(flags);
	}

	@Override
	public String getName() {
		return "CMP";
	}

	@Override
	public void register(CommandSet cset) {
		 cset.defineCommand(0xC9, this, new Immediate());
		 cset.defineCommand(0xC5, this, new ZeroPage());
		 cset.defineCommand(0xD5, this, new ZeroPageX());
		 cset.defineCommand(0xCD, this, new Absolute());
		 cset.defineCommand(0xDD, this, new AbsoluteX());
		 cset.defineCommand(0xD9, this, new AbsoluteY());
		 cset.defineCommand(0xC1, this, new IndirectX());
		 cset.defineCommand(0xD1, this, new IndirectY());
	}

}
